<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2018/9/17
 * Time: 14:51
 */

namespace App\Http\Controllers\Manage;

use App\Http\Controllers\ApiController;
use App\Library\Helper;
use App\Library\Redis\RedisObj;
use App\Models\StSgBlackList;
use App\Models\StSgReturn;
use App\Models\StRemoteRequestUsLog;
use App\Models\StErrorLog;
use App\Models\StSgSendLog;
use App\Models\UserBase;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Storage;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class ImageTransmissionController extends ApiController
{

    protected $cipher;
    protected $mode;
    protected $pad_method;
    protected $encrypt_key;
    protected $decrypt_key;
    protected $iv;
    protected $request;

    public $stSgReturnModel;
    public $stRemoteRequestUsLogModel;
    public $stErrorLogModel;
    public $stSgBlackListModel;
    public $stSgSendLogModel;
    public $stUserBaseModel;

    public $sgApiUrl;
    public $hospitalCD;
    public $passwd;
    public $config;

    public function __construct($method = 'pkcs7', $iv = '', $mode = MCRYPT_MODE_ECB, $cipher = MCRYPT_RIJNDAEL_128, Request $request)
    {
        parent::__construct();
        $hospitalId = $request->input('hospital_id');
        if (Helper::isProduction()) {
            $this->config = config('shanggongProduction');
            $hospitalConf = config('shanggongProduction.hospitals.hospital_' . $hospitalId);
        } else {
            $this->config = config('shanggongTesting');
            $hospitalConf = config('shanggongTesting.hospitals.hospital_' . $hospitalId);
        }
        $this->stSgReturnModel = new StSgReturn();
        $this->stRemoteRequestUsLogModel = new StRemoteRequestUsLog();
        $this->stErrorLogModel = new StErrorLog();
        $this->stSgBlackListModel = new StSgBlackList();
        $this->stSgSendLogModel = new StSgSendLog();
        $this->stUserBaseModel = new UserBase();

        // 加密key
        $this->encrypt_key = $hospitalConf['encrypt_key'];
        // 解密key
        $this->decrypt_key = $hospitalConf['decrypt_key'];
        $this->pad_method = $method;
        $this->iv = $iv;
        $this->mode = $mode;
        $this->cipher = $cipher;

        //调用接口的平台服务 测试 地址
        $this->sgApiUrl = $hospitalConf['sgApiUrl'];
        $this->hospitalCD = $hospitalConf['hospitalCD'];
        $this->passwd = $hospitalConf['passwd'];
    }

    public function test(Request $request)
    {
        if (Helper::isProduction()) {
            return;
        }
        $redisObj = RedisObj::instance();
        $hId = $request->input('hid');
        $dId = $request->input('did');
        $hosKey = 'sg_hospital_id_' . $hId;
        $docKey = 'sg_doctor_id_' . $dId;

        $redisObj->delete($hosKey);
        $redisObj->delete($docKey);

//        $type = $request->input('type');
//        if ($type == 1) {
//            phpinfo();
//        } else {
//            $redisObj = RedisObj::instance();
//            $redisObj->set('a', 33);
//            $a = $redisObj->get('a');
//            var_dump($a);die();
//        }
//


//        $ip = Helper::getClientIp();
//        Auth::user()->hospital->getAbilities()->pluck('name');
//        $id = Auth::user()->id;
//        echo "<pre>";print_r($ip);echo "<pre>";die();

//        Helper::checkSecuritySg();
    }

    private function pad_or_unpad($str, $ext)
    {
        if (!is_null($this->pad_method)) {

            $func_name = __CLASS__ . '::' . $this->pad_method . '_' . $ext . 'pad';

            if (is_callable($func_name)) {

                $size = mcrypt_get_block_size($this->cipher, $this->mode);

                return call_user_func($func_name, $str, $size);
            }
        }

        return $str;
    }

    private function pad($str)
    {
        return $this->pad_or_unpad($str, '');
    }

    private function unpad($str)
    {
        return $this->pad_or_unpad($str, 'un');
    }

    private function encrypt($str)
    {
        $str = $this->pad($str);

        $td = mcrypt_module_open($this->cipher, '', $this->mode, '');

        if (empty($this->iv)) {

            $iv = @mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);

        } else {

            $iv = $this->iv;

        }

        mcrypt_generic_init($td, $this->encrypt_key, $iv);

        $cyper_text = mcrypt_generic($td, $str);

        $rt = base64_encode($cyper_text);

        mcrypt_generic_deinit($td);

        mcrypt_module_close($td);

        return $rt;
    }

    private function decrypt($str)
    {
        $td = mcrypt_module_open($this->cipher, '', $this->mode, '');

        if (empty($this->iv)) {

            $iv = @mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);

        } else {

            $iv = $this->iv;

        }

        mcrypt_generic_init($td, $this->decrypt_key, $iv);

        $decrypted_text = mdecrypt_generic($td, base64_decode($str));

        $rt = $decrypted_text;


        mcrypt_generic_deinit($td);

        mcrypt_module_close($td);

        return $this->unpad($rt);
    }

    private static function pkcs7_pad($text, $blocksize)
    {
        $pad = $blocksize - (strlen($text) % $blocksize);

        return $text . str_repeat(chr($pad), $pad);
    }

    private static function pkcs7_unpad($text)
    {
        $pad = ord($text[strlen($text) - 1]);

        if ($pad > strlen($text)) return false;

        if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false;

        return substr($text, 0, -1 * $pad);
    }

    // 限制医院30分钟30次，一个医生10分钟3次
    private function checkSecuritySg($hospitalId)
    {
        $uid = Auth::user()->id;
        $userInfo = $this->stUserBaseModel->getOne(['type'], ['id' => $uid]);
        if (empty($userInfo) || $userInfo['type'] === 1) {
            return 1;
        }

        $checkDbRes = $this->checkDb($hospitalId, $uid);
        if ($checkDbRes) {
            return 1;
        }

        $checkDoctorRes = $this->checkDoctor($uid);
        if ($checkDoctorRes) {
            return 1;
        }
        $checkHospitalRes = $this->checkHospital($hospitalId);
        if ($checkHospitalRes) {
            return 1;
        }

        return 0;
    }
    private function checkDb($hospitalId, $doctorId)
    {
        $isExitHosRes = $this->stSgBlackListModel->isExitHospital($hospitalId);
        if ($isExitHosRes) {
            return 1;
        }
        $isExitDocRes = $this->stSgBlackListModel->isExitDoctor($doctorId);
        if ($isExitDocRes) {
            return 1;
        }

        return 0;
    }
    private function checkHospital($hospitalId)
    {
        $redisObj = RedisObj::instance();
        $timeLength = $this->config['hospital_per_time_length'];

        $key = 'sg_hospital_id_' . $hospitalId;
        if ($redisObj->exists($key)) {
            $count = $redisObj->incr($key);
            if ($count > $this->config['hospital_per_time_chance']) {
                $this->stSgBlackListModel->addOneHospital($hospitalId);
                return 1;
            }
        } else {
            $redisObj->incr($key);
            $redisObj->setexpire($key, 60 * $timeLength);
        }

        return 0;
    }
    private function checkDoctor($doctorId)
    {
        $redisObj = RedisObj::instance();
        $timeLength = $this->config['doctor_per_time_length'];

        $key = 'sg_doctor_id_' . $doctorId;
        if ($redisObj->exists($key)) {
            $count = $redisObj->incr($key);
            if ($count > $this->config['doctor_per_time_chance']) {
                $this->stSgBlackListModel->addOneDoctor($doctorId);
                return 1;
            }
        } else {
            $redisObj->incr($key);
            $redisObj->setexpire($key, 60 * $timeLength);
        }

        return 0;
    }
    // 文件上传方法
    public function uploadImgSg(Request $request)
    {
        if (
            $request->hasFile('image') &&
            $request->file('image')->isValid()
        ) {
            $file = $request->file('image');
            if ($file->getClientSize() > 10 * 1024 * 1024) {
                return response(['code' => -2, 'message' => '文件大小不能超过10M','data'=>[]]);
            }

            // 获取文件相关信息
            $originalName = $file->getClientOriginalName(); // 文件原名
            $ext = $file->getClientOriginalExtension();     // 扩展名
            $realPath = $file->getRealPath();   //临时文件的绝对路径
            $type = $file->getMimeType();// image/jpeg | image/png
            if ($type != 'image/jpeg' && $type != 'image/png') {
                return response(['code' => -3, 'message' => '文件格式必须是jpg或者png','data'=>[]]);
            }
            // 上传文件
            $filename = date('Y-m-d-H-i-s') . '-' . uniqid() . '.' . $ext;
            // 使用uploads本地存储目录
            $bool = Storage::disk('uploads')->put($filename, file_get_contents($realPath));

            if ($bool) {
                return response([
                    'code' => 10000,
                    'message' => '上传成功',
                    'data' => [
                        'url' => storage_path('app/public/uploads/').$filename
                    ]
                ]);
            }
        }

        return response(['code' => -1, 'message' => '上传失败','data'=>[]]);
    }

    public function deleteImgSg(Request $request)
    {
        $bool = Storage::disk('uploads')->delete(basename($request['url']));

        if ($bool) {
            return response(['code' => 10000, 'message' => '删除成功','data'=>[]]);
        }

        return response(['code' => -1, 'message' => '删除失败','data'=>[]]);
    }

    // 上工 开始评估 前端post测试
    public function transmission(Request $request)
    {
        try {
            $params = $request->all();
            $validArr = [
                'patient_id' => -10001,
                'record_id' => -10002,
                'name' => -10003,
                'birthday' => -10004,
                'sex' => -10005,
                'complain' => -10006,
                'img_urls' => -10007,
            ];

            foreach ($validArr as $param => $code) {
                if ($param == 'sex' && $params['sex'] == 0) {
                    continue;
                }
                if (empty($params[$param])) {
                    return response(['code' => $code, 'message' => '缺少参数' . $param]);
                }
            }

            $imgUrls = explode(',', $params['img_urls']);
            if (count($imgUrls) != 1 && count($imgUrls) != 2) {
                return response(['code' => -2, 'message' => '图片数量必须是一张或两张！']);
            }
            /*参数验证 end*/

            /* 访问次数限制 start */
            $checkRes = self::checkSecuritySg($request->input('hospital_id'));
            if ($checkRes) {
                return response([
                    'code' => -30000,
                    'message' => '请求过于频繁已被锁定，请联系电话'
                        . $this->config['support_call']
                        . '来解锁继续使用',
                    'data' => []
                ]);
            }
            /* 访问次数限制 end */

            /* 记log start */
            $uid = Auth::user()->id;
            $ip = Helper::getClientIp();
            $this->stSgSendLogModel->insert_db([
                'hospital_id' => $request->input('hospital_id'),
                'uid' => $uid,
                'ip' => $ip,
            ]);
            /* 记log end */

            $post1 = array(
                'HospitalCD' => $this->hospitalCD,// 上工提供
                'Passwd' => $this->passwd,// 上工提供
            );
            /*$content = array(
                "ImageCode" => "20180410143715425",// 回传编号
                "DistinguishCD" => "Distinguish-1",// 只有糖尿病，写死
                "PatientNM" => "test",// 姓名（前端提供）
                "Age" => "-33",// （前端提供）
                "Complain" => "aaa",// 主诉（前端提供）
                "SexCD" => "Sex-1",// Sex-1：男、Sex-2：女（前端提供）
            );*/
            $sexConfig = ['Sex-1', 'Sex-2'];

            $content = [
//            "ImageCode" => "20180410143715425",// 回传编号
                "ImageCode" => date('YmdHis') . uniqid(),
                "DistinguishCD" => "Distinguish-1",// 只有糖尿病，写死
                "PatientNM" => $params['name'],// 姓名（前端提供）
                "Age" => Helper::getAgeByBirthday($params['birthday']),// （前端提供）
                "Complain" => $params['complain'],// 主诉（前端提供）
                "SexCD" => $sexConfig[$params['sex']],// Sex-1：男、Sex-2：女（前端提供）
            ];

            $content['OriginalImg1'] = base64_encode(file_get_contents($imgUrls[0]));
            if (count($imgUrls) == 2) {
                $content['OriginalImg2'] = base64_encode(file_get_contents($imgUrls[1]));
            }
            $post1['Content'] = $this->encrypt(json_encode($content));

            //将数组转成json格式
            $data = json_encode($post1);

            //1.初始化curl句柄
            $ch = curl_init();

            //2.设置curl
            //设置访问url
            curl_setopt($ch, CURLOPT_URL, $this->sgApiUrl);

            //捕获内容，但不输出
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

            //模拟发送POST请求
            curl_setopt($ch, CURLOPT_POST, 1);

            //发送POST请求时传递的参数
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

            //设置头信息
            curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                    'Content-Type: application/json; charset=utf-8',
                    'Content-Length: ' . strlen($data))
            );

            //3.执行curl_exec($ch)
            $return_content = curl_exec($ch);

            //如果获取失败返回错误信息
            if ($return_content === FALSE) {
                $return_content = curl_errno($ch);
            }

            $return_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

            //4.关闭curl
            curl_close($ch);


            $return_content = json_decode($return_content);

            if ($return_content->Status == 0) {
                $insertGetId = $this->stSgReturnModel->insert_db([
                    'patient_id' => $params['patient_id'],
                    'record_id' => $params['record_id'],
                    // 供回调函数更新使用
                    'ImageCode' => $content['ImageCode'],
                ]);
                if ($insertGetId) {
                    return response(['code' => 10000, 'message' => '成功', 'data' => []]);
                }

            }

        } catch (\Exception $e) {
            $this->stErrorLogModel->record($request->path(), $request->all(), $e->getMessage() . '====' . $e->getTraceAsString());
        }

        return response(['code' => -1, 'message' => '发送上工失败', 'data' => []]);
    }


    public function reportReception(Request $request)
    {
        $requestJsonObj = json_decode(
            preg_replace(
                '/{Content/',
                '{"Content"',
                $request->getContent()
            )
        );

        if (empty($requestJsonObj->Content)) {
            return response(['code' => -1, 'message' => '缺少参数Content']);
        }

        $content = $requestJsonObj->Content;

        //解密数据
        $content = $this->decrypt($content);

        try {
            $content = json_decode($content);
            $this->stRemoteRequestUsLogModel->record($request->path(), $content);//记录请求参数

            /* 验证 */
            $validArr = [
                'EyeImageID' => -1,
                'ImageCode' => -2,
                'Distinguish' => -3,
                'PatientNM' => -4,
                'Age' => -5,
                'Complain' => -6,
                'Sex' => -7,
                'PrescriptionDoctor' => -8,
            ];
            foreach ($validArr as $param => $code) {
                if (!isset($content->$param)) {
                    return response(['Status' => $code, 'ResMsg' => $param . '为空 报错', 'Count' => 0]);
                }
            }

            $files = [
                'OriginalImg1' => '.jpg',
                'OriginalImg2' => '.jpg',
                'AnnotationImg1' => '.jpg',
                'AnnotationImg2' => '.jpg',
                'ReportFile' => '.pdf',
            ];

            foreach ($files as $file => $ext) {
                if (!empty($content->$file)) {
                    $fileName = $content->EyeImageID . $file . $ext;
                    Storage::disk('downloads')->put($fileName, base64_decode($content->$file));

                    $content->$file = '/storage/downloads/' . $fileName;
                } else {
                    $content->$file = '';
                }
            }

            // 转array在后，否则太大无法转
            $content = (array)$content;
            // 兼容上工接口里的NULL值
            foreach ($content as &$v) {
                if ($v === NULL) {
                    $v = '';
                }
            }

            /* 入库 */
            DB::beginTransaction();
            try {
                // (1/3).通过当前这次ImageCode查到record_id
                $recordId = $this->stSgReturnModel->getOne(['record_id'], ['ImageCode' => $content['ImageCode']])['record_id'];
                // (2/3).通过record_id查到所有记录，用ImageCode排除当前这次。
                //不管完没完成，全部覆盖，更新成删除。
                $this->stSgReturnModel->updateBy(
                    ['report_status' => 3],
                    [
                        'record_id' => $recordId,
                        'ImageCode !=' => $content['ImageCode'],
                    ]
                );
                // (3/3).通过当前这次ImageCode更新这次的记录。
                $content['report_status'] = 2;
                $this->stSgReturnModel->updateBy($content, ['ImageCode' => $content['ImageCode']]);

                DB::commit();

                return response(['Status' => 0, 'ResMsg' => '返回成功', 'Count' => 1]);
            } catch (\Exception $e) {
                DB::rollback();
                $this->stErrorLogModel->record($request->path(), $content, $e->getMessage().'===='.$e->getTraceAsString());
            }
            
        } catch (\Exception $e) {
            $this->stErrorLogModel->record($request->path(), $content, $e->getMessage().'===='.$e->getTraceAsString());
        }

        return response(['Status' => -2, 'ResMsg' => '数据提交失败', 'Count' => 0]);
    }

    /* 前端查看结果 */
    public function getSgReturnResult(Request $request)
    {
        $params = $request->all();
        $validArr = [
            'record_id' => -10001,
        ];

        foreach ($validArr as $param => $code) {
            if (empty($params[$param])) {
                return response(['code' => $code, 'message' => '缺少参数' . $param]);
            }
        }

        $count = $this->stSgReturnModel->countBy([
            'record_id' => $params['record_id'],
            'report_status' => 2,
        ]);
        if ($count == 1) {
            $result = $this->stSgReturnModel->getOne(
                ['*'],
                ['record_id' => $params['record_id'], 'report_status' => 2]
            );

            if (!empty($result)) {
                return response(['code' => 10000, 'message' => '成功', 'data' => $result]);
            }
        }

        return response(['code' => -1, 'message' => '获取失败', 'data' => []]);
    }
}